package com.flyxiaozhu.erp.service.controllers;

import com.flyxiaozhu.erp.service.annotations.ContextApp;
import com.flyxiaozhu.erp.core.entities.*;
import com.flyxiaozhu.erp.core.libs.*;
import com.flyxiaozhu.erp.core.repositories.GoodsOrderDetailRepository;
import com.flyxiaozhu.erp.core.repositories.GoodsOrderRepository;
import com.flyxiaozhu.erp.core.repositories.GoodsRepository;
import com.flyxiaozhu.erp.core.repositories.GoodsSkuRepository;
import com.flyxiaozhu.erp.core.services.GoodsService;
import com.flyxiaozhu.erp.core.services.GoodsSkuService;
import com.flyxiaozhu.erp.core.utils.BeanUtils;
import com.flyxiaozhu.erp.core.utils.CollectionUtils;
import com.flyxiaozhu.erp.core.utils.SnUtils;
import com.flyxiaozhu.erp.service.forms.OrderForm;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author flyxiaozhu
 * @date 2019-04-26 15:43
 */
@RestController
@Validated
public class OrderController {
    @Autowired
    GoodsOrderRepository goodsOrderRepository;
    @Autowired
    SnUtils snUtils;
    @Autowired
    GoodsSkuRepository goodsSkuRepository;
    @Autowired
    GoodsRepository goodsRepository;
    @Autowired
    GoodsService goodsService;
    @Autowired
    GoodsOrderDetailRepository goodsOrderDetailRepository;
    @Autowired
    GoodsSkuService goodsSkuService;

    /**
     * 下单预检查 参数 eg：[{"goodsId":1,"skuId":1,"num":1}]或[{"goodsId":1,"num":1}]
     *
     * @param goodsData
     * @param request
     * @return
     * @throws AppException
     */
    @RequestMapping(value = "/order/preOrderCheck")
    @SuppressWarnings("unchecked")
    public JSONResult preOrderCheck(@RequestParam(value = "goodsList") String goodsData,
                                    HttpServletRequest request) throws AppException {
        JSONArray goodsDataList = JSONArray.fromObject(goodsData);

        List<Long> skuIds = CollectionUtils.map(goodsDataList, o -> ((JSONObject) o).optLong("skuId", 0L));
        List<Long> goodsIds = CollectionUtils.map(goodsDataList, o -> ((JSONObject) o).getLong("goodsId"));

        //查询SKU
        Map<Long, GoodsSku> goodsSkuMap = CollectionUtils.columnMap(goodsSkuRepository.findByIdIn(skuIds), GoodsSku::getId);
        //查询商品
        Map<Long, Goods> goodsMap = CollectionUtils.columnMap(goodsRepository.findByIdIn(goodsIds), Goods::getId);

        for (Object o : goodsDataList) {
            long goodsId = ((JSONObject) o).getLong("goodsId");
            long skuId = ((JSONObject) o).optLong("skuId", 0);
            int num = ((JSONObject) o).getInt("num");

            Goods goods = goodsMap.get(goodsId);
            if (goods == null || goods.getStatus() != Constants.GOODS_STATUS_NORMAL) {
                return new JSONResult(ErrorCode.NO_DATA, "商品ID错误");
            }

            GoodsSku sku = null;
            if (skuId > 0) {
                sku = goodsSkuMap.get(skuId);
                if (sku == null) {
                    return new JSONResult(ErrorCode.NO_DATA, "SKU ID错误");
                }
            }

            JSONResult result = StockFactory.getRuleInstance(goods.getRuleId()).check(goods, sku, num, request);
            if (result.getCode() != 0) {
                return result;
            }
        }

        return new JSONResult().put("preOrderCheck", true);
    }

    /**
     * 创建订单
     *
     * @param app
     * @param form
     * @param bindingResult
     * @return
     * @throws AppException
     */
    @RequestMapping(value = "/order/create")
    @Transactional(rollbackOn = Exception.class)
    public JSONResult createOrder(@NotNull(message = "应用错误") @ContextApp App app, @Valid OrderForm form, BindingResult bindingResult, HttpServletRequest request) throws AppException {
        if (bindingResult.hasErrors()) {
            return new JSONResult(bindingResult);
        }
        if (goodsOrderRepository.findByOutTradeNoOnLock(form.getOutTradeNo()) != null) {
            return new JSONResult(ErrorCode.DUPLICATE_KEY, "订单号已存在");
        }

        // 生成订单编号并保存
        String orderSn = snUtils.buildSn(SnUtils.BusinessCode.SHOPPING_ORDER);

        GoodsOrder order = new GoodsOrder();
        BeanUtils.copyProperties(form, order);

        order.setAppId(app.getId());
        order.setOrderSn(orderSn);

        try {
            order.setDetails(buildGoodsDetail(form.getGoodsList()));
        } catch (AppException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            return new JSONResult(ErrorCode.INVALID_PARAM, "商品数据错误");
        }

        // 保存价格
        long totalSellingAmount = 0;
        totalSellingAmount = CollectionUtils.reduce(order.getDetails(), totalSellingAmount, (o, result) -> o.getSellingAmount() + result);
        order.setSellingAmount(totalSellingAmount);
        order.setTotalAmount(order.getSellingAmount() + order.getCarriage());

        order = goodsOrderRepository.save(order);

        for (GoodsOrderDetail detail : order.getDetails()) {
            detail.setOrderId(order.getId());
            goodsOrderDetailRepository.save(detail);

            Goods goods = goodsRepository.findByIdOnLock(detail.getGoodsId()); // 读取的时候使用乐观琐，因为下单请求多，悲观琐-写多读少，乐观琐-读多写少
            GoodsSku sku = detail.getSkuId() > 0 ? goodsSkuRepository.findByIdOnLock(detail.getSkuId()) : null;

            JSONResult result = StockFactory.getRuleInstance(goods.getRuleId())
                    .lockStock(order, detail, goods, sku, request);

            if (result.getCode() != 0) {
                throw new AppException(result);
            }
        }
        return new JSONResult().put("order", order);
    }

    /**
     * 绑定商品详情数据
     *
     * @param goodsData
     * @return
     * @throws AppException
     */
    @SuppressWarnings("unchecked")
    private List<GoodsOrderDetail> buildGoodsDetail(String goodsData) throws AppException {
        JSONArray goodsDataList = JSONArray.fromObject(goodsData);

        List<Long> skuIds = CollectionUtils.map(goodsDataList, o -> ((JSONObject) o).optLong("skuId", 0L));
        List<Long> goodsIds = CollectionUtils.map(goodsDataList, o -> ((JSONObject) o).getLong("goodsId"));

        //查询SKU
        List<GoodsSku> goodsSkus = goodsSkuRepository.findByIdIn(skuIds);
        Map<Long, GoodsSku> goodsSkuMap = CollectionUtils.columnMap(goodsSkus, GoodsSku::getId);
        //查询商品
        List<Goods> goodsList = goodsRepository.findByIdIn(goodsIds);
        Map<Long, Goods> goodsMap = CollectionUtils.columnMap(goodsList, Goods::getId);

        List<GoodsOrderDetail> result = new ArrayList<>();
        for (int i = 0; i < goodsDataList.size(); i++) {
            JSONObject item = goodsDataList.getJSONObject(i);

            GoodsOrderDetail detail = new GoodsOrderDetail();
            GoodsSku sku = null;

            Goods goods = goodsMap.get(item.getLong("goodsId"));
            if (goods == null) {
                throw new AppException(ErrorCode.INVALID_PARAM, "商品ID错误");
            }
            long skuId = item.optLong("skuId", 0L);
            if (skuId != 0) {
                sku = goodsSkuMap.get(item.optLong("skuId", 0L));
                if (sku == null) {
                    throw new AppException(ErrorCode.INVALID_PARAM, "SKU ID错误");
                }
            } else {
                if (goods.getHasMultiSku()) {
                    throw new AppException(ErrorCode.INVALID_PARAM, "请使用SKU ID进行下单");
                }
            }
            if (goods.getStatus() != Constants.COMMON_STATUS_NORMAL) {
                throw new AppException(ErrorCode.STATUS_ERROR, "商品状态错误");
            }

            long sellingPrice = skuId == 0 ? goods.getSellingPrice() : sku.getSellingPrice();

            detail.setGoodsId(goods.getId());
            detail.setGoodsNo(goods.getGoodsNo());
            detail.setGoodsName(goods.getName());
            detail.setGoodsNum(item.getInt("num"));
            detail.setGoodsThumb(goods.getThumb());
            detail.setSkuId(skuId);
            detail.setSkuDesc(skuId == 0 ? "" : sku.getSkuDesc());
            detail.setSellingPrice(sellingPrice);
            detail.setSellingAmount(sellingPrice * item.getInt("num"));

            result.add(detail);
        }
        return result;
    }

    /**
     * 更新订单状态
     *
     * @param app
     * @param form
     * @param bindingResult
     * @return
     */
    @RequestMapping(value = "/order/update")
    @Transactional(rollbackOn = Exception.class)
    public JSONResult updateOrder(@NotNull(message = "应用错误") @ContextApp App app, @Valid OrderForm form, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return new JSONResult(bindingResult);
        }
        GoodsOrder order = goodsOrderRepository.findByOutTradeNoOnLock(form.getOutTradeNo());
        if (order == null || order.getAppId() != app.getId()) {
            return new JSONResult(ErrorCode.NO_DATA, "订单号错误");
        }

        int oldStatus = order.getStatus();

        BeanUtils.copyProperties(form, order);
        goodsOrderRepository.save(order);

        List<Integer> failedStatus = new ArrayList<>();
        failedStatus.add(Constants.ORDER_STATUS_CLOSED);
        failedStatus.add(Constants.ORDER_STATUS_EXCEPTION);
        failedStatus.add(Constants.ORDER_STATUS_FAILED);

        //由正常转入失败时，检查是否需要退货
        if (!failedStatus.contains(oldStatus) && failedStatus.contains(order.getStatus())) {
            List<GoodsOrderDetail> detailList = goodsOrderDetailRepository.findByOrderId(order.getId());
            for (GoodsOrderDetail detail : detailList) {
                //已发货、已完成、已锁定库存
                if (detail.getDeliveryStatus() == Constants.DELIVERY_STATUS_SENT
                        || detail.getDeliveryStatus() == Constants.DELIVERY_STATUS_COMPLETED
                        || detail.getDeliveryStatus() == Constants.DELIVERY_STATUS_LOCKED) {
                    Goods goods = goodsService.findById(detail.getGoodsId());
                    if (goods != null) {
                        GoodsSku sku = null;
                        if (detail.getSkuId() != 0) {
                            sku = goodsSkuService.findById(detail.getSkuId());
                        }
                        try {
                            StockFactory.getRuleInstance(goods.getRuleId())
                                    .refund(order, detail, goods, sku, null);
                        } catch (AppException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        return new JSONResult().put("order", order);
    }
}
